package com.oly.cms.user.security.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import static org.springframework.security.config.Customizer.withDefaults;

import com.oly.cms.common.constant.OlySystemConstant;
import com.oly.cms.user.filter.WebCaptchaAuthenticationFilter;
import com.oly.cms.user.filter.WebJwtAuthenticationTokenFilter;
import com.oly.cms.user.security.hand.MyAuthenticationFailureHandler;
import com.oly.cms.user.security.hand.MyAuthenticationSuccessHandler;
import com.oly.cms.user.security.hand.MyLogoutSuccessHandler;
import com.oly.cms.user.security.hand.RedisTokenRepositoryImpl;
import com.oly.cms.user.security.hand.WebAuthenticationEntryPointImpl;
import com.oly.cms.user.security.service.WebUserDetailsService;

/**
 * spring security配置
 * 
 * @author grace
 */
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Configuration
public class WebSecurityConfig{

    /**
     * 自定义用户认证逻辑
     */
    @Autowired
    private WebUserDetailsService userDetailsService;

    @Autowired
    private WebJwtAuthenticationTokenFilter webJwtAuthenticationTokenFilter;

    // @Autowired
    // private CustomAuthenticationDetailsSource authenticationDetailsSource;

    // @Autowired
    // private CustomAuthenticationProvider authenticationProvider;

    @Autowired
    private MyAuthenticationFailureHandler failureHandler;

    @Autowired
    private MyAuthenticationSuccessHandler successHandler;

    @Autowired
    private MyLogoutSuccessHandler logoutOutHandler;

    @Autowired
    private RedisTokenRepositoryImpl repository;

   

    /**
     * 配置HTTP安全设置，定义Spring Security的访问规则和行为。
     * 
     * @param http 用于配置HttpSecurity的接口，可定制应用程序的请求处理方式，例如认证、授权、CSRF保护等。
     * @throws Exception 如果配置过程中发生错误，则抛出异常。
     */
    @Bean
    protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        
        return httpSecurity.csrf(csrf -> csrf.disable())
                 // 添加认证异常入口
                .exceptionHandling(handling -> handling.authenticationEntryPoint(new WebAuthenticationEntryPointImpl()))
                .authorizeRequests(requests -> requests
                        // 允许匿名访问
                        .antMatchers(HttpMethod.GET, "/**", "/static/**", "/*/user/register", "/*/api/**")
                        .permitAll()
                        // 允许匿名访问
                        .antMatchers(HttpMethod.POST,OlySystemConstant.THEME_MANAGE_URL_PREFIX+ "/**", "/*/user/register", "/*/general/**",
                                "/*/user/**")
                        .permitAll()
                        // 需要认证
                        .antMatchers(HttpMethod.POST, "/*/hand/**", "/*/register").authenticated()
                        .anyRequest().authenticated())
                .formLogin(login -> login
                        // loginPage 登录页面 loginProcessingUrl 登录处理
                        .loginPage("/*/login").permitAll().loginProcessingUrl("/*/doLogin").permitAll()
                        //.authenticationDetailsSource(authenticationDetailsSource)
                        )
                // 启用记住密码
                .authorizeRequests(withDefaults())
                .rememberMe(me -> me.tokenValiditySeconds(5 * 24 * 60 * 60).tokenRepository(repository)
                        .userDetailsService(userDetailsService))
                .logout(logout -> logout.logoutUrl("/*/logout").logoutSuccessHandler(logoutOutHandler))
                //.authenticationProvider(authenticationProvider)
                // 添加JWT filter
                .addFilterBefore(webJwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .build();
    }

    /**
     * 强散列哈希加密实现
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

   

    /**
     *身份验证实现
     */
    @Bean
    public AuthenticationManager authenticationManager() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder());
        return new ProviderManager(daoAuthenticationProvider);
    }
     
    /**
     * 登录验证码拦截器
     * @return
     * @throws Exception
     */
    @Bean
    WebCaptchaAuthenticationFilter customAuthenticationFilter() throws Exception {
        WebCaptchaAuthenticationFilter filter = new WebCaptchaAuthenticationFilter();
        filter.setAuthenticationManager(authenticationManager());
        //若果配置中配置处理路径,此处必须要一致
        filter.setFilterProcessesUrl("/*/doLogin");
        filter.setAuthenticationSuccessHandler(successHandler);
        filter.setAuthenticationFailureHandler(failureHandler);
        return filter;
    }

}
